
(in-package :oali.proto)



;;
;; simple unit-testing framework
;;

(defvar *test-name* nil)

(defvar *test-report-stream* *standard-output*)

(defmacro deftest (name parameters &body body)
  "Define a test function. Within a test function we can call
   other test functions or use 'check' to run individual test
   cases."
  `(defun ,name ,parameters
    (let ((*test-name* (append *test-name* (list ',name))))
      ,@body)))

(defmacro report-result (expr)
  "Report the results of a single test case"
  (let* ((func-name (car expr))
	 (params (cdr expr))
	 (result (gensym "result-"))
	 (arg-names (loop for i in params for j from 0 collect
			  (gensym (format nil "arg-~a-" j)))))
    `(let* (,@(loop for arg in arg-names for j from 0 collect
		    `(,arg ,(nth j params)))
	    (,result (,func-name ,@arg-names)))
       (format *test-report-stream* "~:[FAIL~;pass~] ~a: ~a" ,result *test-name* ',expr)
       (if (and (null ,result) ',arg-names)
	   (format *test-report-stream* ", evaluated args: ~a" (list ,@arg-names)))
       (write-char #\Newline *test-report-stream*)
       ,result)))

(defmacro check (&body forms)
  "Run each expression in 'forms' as a test case."
  `(combine-results
    ,@(loop for f in forms collect `(report-result ,f))))

(defmacro combine-results (&body forms)
  "Combine the results (as booleans) of evaluating 'forms' in order."
  (let ((result (gensym "result")))
    `(let ((,result t))
      ,@(loop for f in forms collect `(unless ,f (setf ,result nil)))
      ,result)))



;;
;; tests #2 entries
;;

(defun p-iter2-tests ()
  (let* ((parser (make-instance 'parser-context))
	 (interpreter (make-instance 'interpreter-context :parser-context parser))
	 (c-compiler (make-instance 'c-compiler-context :parser-context parser)))

    (add-builtins parser)

    ;; accept test func
    (accept-func parser '(func foo (a b) (+ a (* b 2))))
    
    ;; print test func
    (format t "foo (3, 10) = ~a~%" (wrapped-call interpreter 'foo 3 10))

    (c-compile-func c-compiler 'foo)
        
    ;; end
    t))

(deftest test-util ()
  (check (equal (collect-cons (c1 c2)
		  (c1 1) (c1 2) (c1 3)
		  (c2 10)
		  (list c1 c2))
		'((1 2 3) (10))))
  
  (check (equal (parse-lambda-list '(a b c)) '(a b c)))
  
  (check (equal (parse-lambda-list '(a b &rest c)) '(a b c))))


;;
;; run tests entry point
;;
(defun run-tests ()
  (test-util)
  (p-iter2-tests)
  (format t "end run tests~%"))
